Перейти к основному содержимому

7.04. Справочник по Loki

Разработчику Архитектору Инженеру

Справочник по Loki

Loki — это система логирования, разработанная Grafana Labs, ориентированная на эффективное хранение, индексирование и запрос логов без полнотекстового поиска. Она оптимизирована для работы в связке с Prometheus и Grafana, используя те же принципы меток (labels) для организации данных. Loki не индексирует содержимое строк логов, а только их метки, что снижает потребление ресурсов и упрощает масштабирование.

Архитектура Loki

Loki состоит из нескольких компонентов, которые могут быть развернуты как отдельные микросервисы или объединены в один бинарный файл (loki или loki-simple-scalable). Основные компоненты:

Distributor

Принимает входящие логи от клиентов (например, Promtail, Fluentd, Vector).

  • Валидирует структуру записей.
  • Проверяет соответствие меток ограничениям.
  • Распределяет потоки по ingester’ам на основе хэша меток.
  • Поддерживает gRPC и HTTP интерфейсы.

Ключевые параметры:

  • distributor.replication_factor — количество копий каждой записи, отправляемых в разные ingester’ы (по умолчанию 3).
  • distributor.max_recv_msg_size — максимальный размер входящего gRPC-сообщения.
  • distributor.max_concurrent_streams — лимит одновременных потоков gRPC.

Ingester

Принимает логи от distributor’а и временно хранит их в памяти или на диске до их отправки в долговременное хранилище.

  • Отвечает за сжатие, индексацию меток и создание блоков.
  • Участвует в кворуме при записи (при replication_factor > 1).
  • Может работать в WAL-режиме (Write-Ahead Log) для отказоустойчивости.

Ключевые параметры:

  • ingester.lifecycler.ring.store — тип хранилища для ring (consul, etcd, inmemory, memberlist).
  • ingester.max_chunk_age — максимальное время жизни чанка перед флашем (по умолчанию 1 час).
  • ingester.flush_op_timeout — таймаут операции флаша блока.
  • ingester.wal.enabled — включение WAL для защиты от потерь при перезапуске.
  • ingester.wal.dir — путь к директории WAL.
  • ingester.chunk_idle_period — период неактивности чанка, после которого он флашится.

Querier

Обрабатывает запросы LogQL от пользователей или Grafana.

  • Запрашивает данные у ingester’ов («hot» данные) и из хранилища («cold» данные).
  • Объединяет результаты и возвращает клиенту.
  • Кэширует индексы и чанки при включённом кэшировании.

Ключевые параметры:

  • querier.query_timeout — максимальное время выполнения запроса.
  • querier.max_concurrent — лимит одновременных запросов.
  • querier.ingesters_client.grpc_client_config — настройки gRPC-соединения с ingester’ами.
  • querier.cache_results — включение кэширования результатов запросов.

Query Frontend

Опциональный компонент для ускорения и масштабирования запросов.

  • Разбивает большие запросы на подзапросы по времени.
  • Кэширует результаты (в Memcached, Redis и т.п.).
  • Поддерживает очередь запросов и rate limiting.

Ключевые параметры:

  • frontend.query_range.response_cache_config — конфигурация кэша ответов.
  • frontend.split_queries_by_interval — интервал, по которому разбиваются запросы (например, 15m).
  • frontend.max_outstanding_per_tenant — максимальное число запросов на тенант.

Compactor

Отвечает за очистку, удаление старых данных и компактизацию блоков в хранилище.

  • Удаляет блоки по истечении TTL.
  • Объединяет мелкие блоки для улучшения эффективности чтения.
  • Работает только в режиме boltdb-shipper или tsdb.

Ключевые параметры:

  • compactor.retention_enabled — включение политики хранения.
  • compactor.retention_delete_delay — задержка перед удалением данных после окончания срока хранения.
  • compactor.compaction_interval — интервал запуска компактизации.
  • compactor.block_retention — срок хранения блоков (например, 744h).

Index Gateway

Используется в масштабируемых развертываниях (tsdb backend).

  • Загружает индексы из объектного хранилища в память.
  • Обслуживает запросы querier’а без прямого доступа к хранилищу.
  • Уменьшает нагрузку на объектное хранилище.

Ключевые параметры:

  • index_gateway.shard_by_tenant — разделение индексов по тенантам.
  • index_gateway.sync_dir — директория для синхронизации индексов.

Конфигурация Loki

Основной конфигурационный файл — loki.yaml. Он содержит секции для каждого компонента и общие настройки.

auth_enabled

Указывает, включена ли аутентификация по tenant ID.

  • Тип: boolean
  • По умолчанию: false
  • При true каждый запрос должен содержать заголовок X-Scope-OrgID.

server

Настройки HTTP/gRPC сервера.

  • http_listen_port — порт для HTTP API (по умолчанию 3100).
  • grpc_listen_port — порт для gRPC (по умолчанию 9095).
  • grpc_server_max_recv_msg_size — максимальный размер получаемого gRPC-сообщения.
  • grpc_server_max_send_msg_size — максимальный размер отправляемого gRPC-сообщения.

common

Общие параметры для всех компонентов.

  • path_prefix — корневая директория для временных файлов.
  • replication_factor — фактор репликации (по умолчанию 3).
  • ring — настройки распределённого ring’а (consul/etcd/memberlist).
  • storage — конфигурация объектного хранилища (S3, GCS, Azure, filesystem и др.).

storage_config

Определяет, где хранятся чанки и индексы.

schema

  • configs — список схем с указанием периода действия и типа backend’а.
  • Пример:
    - from: "2020-10-24"
    store: tsdb
    object_store: s3
    schema: v13

tsdb_shipper

  • active_index_directory — директория для активных индексов.
  • cache_location — путь к кэшу индексов.
  • shared_store — тип хранилища (s3, gcs, azure, filesystem).

boltdb_shipper

Устаревший, но ещё поддерживаемый backend.

  • active_index_directory — рабочая директория.
  • cache_location — кэш индексов.
  • shared_store — тип хранилища.

filesystem

Для тестовых сред.

  • directory — путь к директории хранения.

aws

Для S3-совместимых хранилищ.

  • bucketnames — имя бакета.
  • endpoint — URL S3-совместимого сервиса.
  • region — регион.
  • access_key_id / secret_access_key — учётные данные.
  • s3forcepathstyle — использовать path-style URL.

azure

  • container_name — имя контейнера.
  • account_name / account_key — учётные данные.

gcs

  • bucket_name — имя бакета.
  • service_account — JSON-ключ сервисного аккаунта.

LogQL — язык запросов Loki

LogQL — это язык, похожий на PromQL, но предназначенный для логов. Состоит из двух частей: selector и pipeline.

Log stream selector

Выбирает потоки логов по меткам.

  • {job="api"} — все логи с меткой job="api".
  • {cluster="prod", namespace=~"app.*"} — регулярное выражение для значения метки.
  • {filename!~".*test.*"} — исключение по регулярному выражению.

Line filters

Фильтрация по содержимому строки.

  • |~ "error" — строки, содержащие "error".
  • |= "timeout" — точное совпадение.
  • |~ "(?i)exception" — case-insensitive через регулярное выражение.
  • | json — парсинг JSON-строк.
  • | logfmt — парсинг в формате logfmt.

Parser expressions

  • | json — автоматический парсинг JSON.
  • | json field1, field2 — выбор конкретных полей.
  • | pattern "<ip> - - <_> \"<method> <uri> ..." — шаблонный парсинг.
  • | regexp "(?P<ip>\\d+\\.\\d+\\.\\d+\\.\\d+).*" — регулярное выражение с именованными группами.

Metric queries

Преобразование логов в метрики.

  • count_over_time({job="api"}[5m]) — количество строк за 5 минут.
  • rate({job="api"}[5m]) — скорость поступления строк.
  • avg by (level) (rate({job="api"}[5m])) — агрегация по метке.

Functions

  • line_format "{{.message}} [{{.level}}]" — переформатирование строки.
  • unwrap field — извлечение числового поля для метрик.
  • label_format level=error`` — изменение метки.
  • drop level — удаление метки.
  • keep filename — оставить только указанные метки.

Режимы развертывания

Monolithic (single binary)

Все компоненты в одном процессе. Подходит для тестирования и небольших сред.

  • Запуск: loki -config.file=loki.yaml

Simple Scalable

Разделение на write-path и read-path.

  • Write: distributor + ingester
  • Read: querier + query-frontend

Microservices

Полное разделение всех компонентов. Требует внешнего координатора (Consul, Etcd, Memberlist).

Mode: TSDB

Современный режим хранения, использующий локальный TSDB-движок.

  • Блоки хранятся в объектном хранилище.
  • Индексы управляются через index-gateway или querier.
  • Поддерживает retention и compaction.

Безопасность

Аутентификация

  • Поддержка multi-tenancy через заголовок X-Scope-OrgID.
  • Интеграция с OAuth2, OpenID Connect через reverse proxy (например, NGINX, Oauth2-proxy).

Шифрование

  • TLS для gRPC и HTTP.
  • Шифрование данных в объектном хранилище (на стороне провайдера или через KMS).

RBAC

  • Управление доступом реализуется внешними средствами (Grafana Enterprise, OPA, reverse proxy).

Производительность и масштабирование

Chunk targeting

  • Целевой размер чанка: ~1.5 МБ.
  • Чанки флашатся при достижении размера или по таймауту.

Rate limiting

  • Ограничение по tenant’ам через ruler или query-frontend.
  • Настройки: max_global_streams_per_user, ingestion_rate_mb.

Caching

  • Индексы: Memcached, Redis.
  • Результаты запросов: Memcached, in-memory.
  • Конфигурация через cache секции в query_range, frontend, querier.

Retention

  • Управление сроком хранения через compactor.
  • Минимальный retention: 24 часа.
  • Удаление происходит асинхронно с задержкой.

Клиенты и отправка логов в Loki

Loki не принимает логи напрямую от приложений — для этого используются агенты-коллекторы.

Promtail

Официальный агент от Grafana Labs.

  • Читает файлы логов с диска.
  • Добавляет метки на основе путей, регулярных выражений или статических значений.
  • Поддерживает обнаружение новых файлов (через glob-паттерны).
  • Отправляет данные в Loki через HTTP/gRPC.
  • Сохраняет позицию чтения в WAL или файле состояния (positions.yaml).

Ключевые параметры в promtail.yaml:

  • server.http_listen_port — порт HTTP-сервера Promtail (по умолчанию 9080).
  • positions.filename — путь к файлу с позициями чтения.
  • clients.url — URL Loki (например, http://loki:3100/loki/api/v1/push).
  • scrape_configs — конфигурация источников логов.

Пример scrape_config:

scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*.log

Добавление меток через pipeline:

pipeline_stages:
- regex:
expression: '^(?P<ip>\S+) - - \[(?P<timestamp>[^\]]+)\] "(?P<method>\S+) (?P<uri>\S+)'
- labels:
method:
uri:
- timestamp:
source: timestamp
format: "02/Jan/2006:15:04:05 -0700"

Fluentd / Fluent Bit

Поддерживают плагин out_loki.

  • Fluent Bit легче и быстрее, подходит для edge-устройств.
  • Оба позволяют парсить JSON, logfmt, регулярные выражения.
  • Метки задаются через теги или фильтры.

Vector

Современный высокопроизводительный агент.

  • Поддерживает преобразования, фильтрацию, маршрутизацию.
  • Может отправлять в Loki, Prometheus, Elasticsearch и др.
  • Конфигурация в TOML или YAML.

Пример sink в Vector:

[sinks.loki]
type = "loki"
inputs = ["app_logs"]
endpoint = "http://loki:3100"
encoding.codec = "json"
labels = { component = "web", env = "prod" }

Форматы данных в Loki

Log Entry

Структура одной записи:

  • Timestamp — временная метка в наносекундах Unix.
  • Line — строка лога (неиндексируемый текст).
  • Labels — набор пар key="value" (индексируются).

Пример:

{job="api", level="error"} 1700000000000000000 "Failed to connect to DB"

Chunk

Группа записей одного потока за определённый период.

  • Хранится в сжатом виде (gzip, snappy, lz4).
  • Имеет временные границы (from, through).
  • После флаша становится неизменяемым блоком.

Index

Хранит соответствие между метками и списком чанков.

  • В режиме tsdb — это локальные TSDB-индексы.
  • В режиме boltdb-shipper — BoltDB-файлы, загружаемые в память.

Метрики и мониторинг Loki

Loki экспортирует метрики в формате Prometheus. Основные группы:

Distributor

  • loki_distributor_received_samples_total — общее число полученных строк.
  • loki_distributor_bytes_received_total — объём принятых данных.
  • loki_distributor_ingester_appends_failures_total — ошибки отправки в ingester.

Ingester

  • loki_ingester_chunks_created_total — число созданных чанков.
  • loki_ingester_chunks_flushed_total — число флашенных чанков.
  • loki_ingester_memory_chunks — количество чанков в памяти.
  • loki_ingester_memory_streams — число активных потоков.

Querier

  • loki_querier_store_query_duration_seconds — время запроса к хранилищу.
  • loki_querier_lines_per_query — среднее число строк на запрос.
  • loki_querier_queries_total — общее число запросов.

Compactor

  • loki_compactor_blocks_marked_for_deletion_total — блоки, помеченные на удаление.
  • loki_compactor_blocks_cleaned_total — успешно удалённые блоки.

Рекомендуется настроить алерты на:

  • Высокий уровень ошибок записи.
  • Задержки флаша чанков.
  • Превышение лимита памяти в ingester’ах.
  • Долгие запросы (>30 сек).

Диагностика и отладка

Проверка меток

Используйте Grafana Explore → Log browser, чтобы увидеть доступные метки и значения.

Поиск «горячих» потоков

Запрос:

count_over_time({job=~".+"}[1h]) 
| sort_desc
| limit 10

Проверка WAL

Если включён WAL, проверьте директорию ingester.wal.dir.

  • При старте Loki восстанавливает чанки из WAL.
  • Не удаляйте WAL вручную — это приведёт к потере данных.

Логирование самого Loki

Loki пишет логи в stderr. Уровень логирования задаётся через:

server:
log_level: info # debug, info, warn, error

В режиме debug видны детали распределения потоков, ошибки gRPC и т.д.


Миграция между схемами хранения

Loki использует понятие schema, определяющее формат индексов и чанков.

Поддерживаемые схемы

  • v9v11 — устаревшие (BoltDB, Cassandra).
  • v12 — переходный (BoltDB + объектное хранилище).
  • v13 — современный (TSDB или Shipper-based).

Как мигрировать

  1. Добавьте новую запись в storage_config.schema.configs с новой датой from.
  2. Запустите Loki — он будет писать новые данные по новой схеме.
  3. Старые данные остаются читаемыми, но не переписываются.
  4. Для полной миграции используйте loki tools migrate.

Важно: нельзя менять схему задним числом. Все изменения применяются только к будущим данным.


Best Practices

Метки

  • Используйте мало уникальных значений (не более 10⁵ на tenant).
  • Избегайте меток с высокой кардинальностью: user_id, request_id, trace_id.
  • Предпочитайте фильтрацию в LogQL, а не через метки.

Размер чанков

  • Целевой размер: 1–2 МБ после сжатия.
  • Настройте chunk_target_size и max_chunk_age.

Retention

  • Включайте retention только в production.
  • Устанавливайте compactor.retention_delete_delay ≥ 24 часов.

Безопасность

  • Всегда используйте TLS между компонентами.
  • Ограничивайте ingestion rate на tenant’а через ruler или внешний прокси.

Производительность

  • Используйте query-frontend для кэширования и шардирования запросов.
  • Размещайте index-gateway в отдельных нодах при большом объёме данных.

Пример минимальной конфигурации (monolithic)

auth_enabled: false

server:
http_listen_port: 3100
grpc_listen_port: 9096

common:
path_prefix: /tmp/loki
storage:
filesystem:
directory: /tmp/loki/chunks
replication_factor: 1
ring:
kvstore:
store: inmemory

schema_config:
configs:
- from: 2020-10-24
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h

storage_config:
tsdb_shipper:
active_index_directory: /tmp/loki/tsdb-index
cache_location: /tmp/loki/tsdb-cache
shared_store: filesystem

compactor:
working_directory: /tmp/loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
block_retention: 168h # 7 дней

Продвинутые функции LogQL

Range queries

Запросы с временным диапазоном используются для агрегации логов в метрики.

  • rate({job="api"}[5m]) — скорость поступления строк.
  • count_over_time({job="api"}[1h]) — общее число строк за час.
  • bytes_rate({job="api"}[10m]) — объём данных в байтах в секунду.

Unwrap

Извлекает числовое значение из строки для использования в метрических функциях.

  • | json | unwrap duration_ms — извлекает поле duration_ms.
  • | pattern "took <?ms>" | unwrap ms — извлекает значение из шаблона.

Label operations

  • label_format job=backend`` — переименовывает или задаёт значение метки.
  • keep job, level — оставляет только указанные метки.
  • drop filename — удаляет метку из результата.

Line format

Форматирует вывод строк:

{job="app"} | line_format "{{.message}} [{{.level}} @ {{.ts}}]"

Pipeline stages

Позволяют преобразовывать логи на лету:

  • regex — извлечение полей через регулярные выражения.
  • json — парсинг JSON.
  • logfmt — парсинг формата key=value.
  • timestamp — установка временной метки из поля.
  • labels — добавление динамических меток.
  • match — условная обработка (например, разные пайплайны для error и info).

Пример:

pipeline_stages:
- match:
selector: '{level="error"}'
stages:
- json:
expressions:
error_type: error.type
- labels:
error_type:

Multi-tenancy

Loki поддерживает разделение данных между тенантами через заголовок X-Scope-OrgID.

  • Каждый tenant имеет своё пространство имён.
  • Данные одного tenant’а недоступны другим.
  • Quotas и retention могут настраиваться отдельно на tenant’а.

Включение:

auth_enabled: true

Использование:

  • Все запросы и отправки должны содержать X-Scope-OrgID: tenant-123.
  • Grafana передаёт этот заголовок при настройке datasource с multi-tenancy.

Управление квотами

Loki позволяет ограничивать использование ресурсов на tenant’а:

ingestion_rate_mb

Максимальный объём данных в мегабайтах в секунду.

  • Пример: ingestion_rate_mb: 10 — 10 МБ/с.

ingestion_burst_size_mb

Максимальный размер всплеска (burst) при отправке.

  • Пример: ingestion_burst_size_mb: 100.

max_global_streams_per_user

Максимальное число уникальных потоков (комбинаций меток).

  • Защищает от взрыва кардинальности.

Конфигурация через limits_config:

limits_config:
ingestion_rate_mb: 8
ingestion_burst_size_mb: 16
max_global_streams_per_user: 5000

Отказоустойчивость и репликация

Replication factor

  • Значение ≥ 2 обеспечивает отказоустойчивость записи.
  • При replication_factor: 3 данные записываются в три ingester’а.
  • Чтение выполняется из одного ingester’а, но при его недоступности — из реплик.

WAL (Write-Ahead Log)

  • При включении (ingester.wal.enabled: true) все входящие записи сначала пишутся на диск.
  • При перезапуске ingester восстанавливает чанки из WAL.
  • Рекомендуется для production-сред.

Ring coordination

  • Используется Consul, Etcd или memberlist для координации ingester’ов.
  • Memberlist — встроенный gossip-протокол, не требует внешних зависимостей.
  • Пример для memberlist:
    ring:
    kvstore:
    store: memberlist

Резервное копирование и восстановление

Loki хранит данные в объектном хранилище, которое обычно уже имеет собственные механизмы репликации и резервного копирования. Однако для дополнительной защиты:

Backup chunks and indexes

  • Просто скопируйте содержимое бакета S3/GCS/Azure.
  • Индексы в режиме tsdb — это обычные файлы, их можно архивировать.

Restore

  • Остановите все компоненты Loki.
  • Восстановите данные в исходное хранилище.
  • Запустите Loki — он автоматически обнаружит блоки.

Point-in-time recovery

  • Не поддерживается напрямую.
  • Для точного восстановления используйте snapshot’ы хранилища (например, AWS S3 Object Versioning).

Интеграция с Grafana

Настройка datasource

  1. В Grafana: Connections → Data sources → Add data source → Loki.
  2. URL: http://loki:3100.
  3. При multi-tenancy: указать заголовок X-Scope-OrgID в HTTP-настройках.

Explore

  • Поддержка автозаполнения меток.
  • Просмотр сырых логов и метрик в одном интерфейсе.
  • Возможность сохранять запросы как dashboard panels.

Alerts

  • Loki не генерирует алерты напрямую.
  • Используйте Grafana Alerting с LogQL-запросами:
    count_over_time({job="app", level="error"}[5m]) > 10
  • Алерты срабатывают при превышении порога.

Variables

  • Динамические переменные на основе меток:
    label_values({job=~".+"}, instance)